import React, { useState, useRef, useEffect, useCallback } from 'react';
import { useMount } from 'react-use';
import { Input } from 'antd';
import { convertToNumber, isNumber, setCaretPosition } from './util';

const convert2ValueInfo = (valueStr, needDecimal, decimalPlaces, thousandsSeparator, nonNegative) => {
    const rel = convertToNumber(valueStr, needDecimal, decimalPlaces, null, '');
    if (rel === '-') {
        if (nonNegative) {
            return { value: null, formatValue: '' };
        }

        if (needDecimal) {
            return { value: null, formatValue: '' };
        }

        return { value: rel, formatValue: rel };
    }

    const value = rel ? +rel : rel;
    const formatValue = convertToNumber(rel, needDecimal, decimalPlaces, thousandsSeparator);

    return {
        value,
        formatValue
    };
};

const INPUT_TYPE = {
    KEY_PRESS: 'keyPress',
    COMPOSITION: 'composition'
};

/**
 * 数字输入控件
 * @param value 数值
 * @param onChange
 * @param decimalPlaces 小数位数
 * @param thousandsSeparator 千位分隔符
 * @param { 'right' | 'left' |'center' } align
 * @param {boolean} nonNegative 非负数
 * @param otherProps 其余antd Input 属性
 * @param ref
 * @returns {JSX.Element}
 * @constructor
 */
const NumberInput = (
    {
        value,
        onChange,
        decimalPlaces = '',
        thousandsSeparator = '',
        align = 'right',
        nonNegative = false,
        ...otherProps
    },
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    ref
) => {
    const inputRef = useRef(null);
    const initValue = convert2ValueInfo(value, true, decimalPlaces, thousandsSeparator, nonNegative);
    const [valueInfo, setValueInfo] = useState(initValue);
    const beforeLengthRef = useRef(null);
    const numberStepRef = useRef(0);
    const positionRef = useRef(null);
    const inputTypeRef = useRef(null);

    const onKeyDown = e => {
        const { value: inputVal /* 文本框的值 */, selectionStart /* 光标起始位置 */ } = e.target;
        // 光标前的字符串
        const beforeCaretStr = String(inputVal).substr(0, selectionStart);
        // 去除千分符的字符串长度
        const beforeLength = thousandsSeparator
            ? beforeCaretStr.replace(new RegExp(thousandsSeparator, 'g'), '').length
            : beforeCaretStr.length;

        beforeLengthRef.current = beforeLength;
        numberStepRef.current = e.which === 8 ? -1 : 0;
    };

    const onKeyPress = e => {
        if (nonNegative && e.key === '-') {
            e.preventDefault();
        }
        numberStepRef.current = 1;
        inputTypeRef.current = INPUT_TYPE.KEY_PRESS;
    };

    const onCompositionStart = () => {
        numberStepRef.current = 1;
        inputTypeRef.current = INPUT_TYPE.COMPOSITION;
    };

    const onInputChange = useCallback((inputElement, inputValue) => {
        const newValueInfo = convert2ValueInfo(inputValue, false, decimalPlaces, thousandsSeparator);
        setValueInfo(newValueInfo);
        onChange(newValueInfo.value);
        positionRef.current = {
            inputElement,
            formatValue: newValueInfo.formatValue,
            beforeLength: beforeLengthRef.current + numberStepRef.current,
            thousandsSeparator
        };
    });

    const onSelect = () => {
        if (positionRef.current) {
            const positionInfo = positionRef.current;
            setCaretPosition(
                positionInfo.inputElement,
                positionInfo.formatValue,
                positionInfo.beforeLength,
                thousandsSeparator
            );
            positionRef.current = null;
        }
    };

    const onBlur = e => {
        if (otherProps.onBlur) {
            otherProps.onBlur(e);
        }
        // 失焦时自动加上小数位
        const newValueInfo = convert2ValueInfo(e.target.value, true, decimalPlaces, thousandsSeparator, nonNegative);
        setValueInfo(newValueInfo);
        onChange(newValueInfo.value);
    };

    const style = {
        ...otherProps.style,
        textAlign: align
    };

    useMount(() => {
        // 传入的值为非数值时，转成数值值
        if (typeof value === 'string' && isNumber(initValue.value)) {
            onChange(initValue.value);
        }
    });

    // 当传进来的值变更时，重新设置格式化的值
    useEffect(() => {
        const newValue = convert2ValueInfo(value, true, decimalPlaces, thousandsSeparator, nonNegative);
        if (
            newValue.value !== valueInfo.value &&
            (valueInfo.value !== '-' || (valueInfo.value === '-' && nonNegative))
        ) {
            setValueInfo(newValue);
            onChange(newValue.value);
        }
    }, [value]);

    useEffect(() => {
        const newValue = convert2ValueInfo(value, true, decimalPlaces, thousandsSeparator, nonNegative);

        if (newValue.value === valueInfo.value && newValue.formatValue !== valueInfo.formatValue) {
            setValueInfo(newValue);
        }
    }, [decimalPlaces, thousandsSeparator, nonNegative]);

    return (
        <Input
            {...otherProps}
            value={valueInfo.formatValue}
            onKeyDown={onKeyDown}
            onKeyPress={onKeyPress}
            onCompositionStart={onCompositionStart}
            onChange={e => {
                const { nativeEvent } = e;

                if (
                    inputTypeRef.current !== INPUT_TYPE.COMPOSITION ||
                    // 中方输入法时，避免在类似"123"再输入4时会出现重复的4
                    (inputTypeRef.current === INPUT_TYPE.COMPOSITION && nativeEvent?.inputType !== 'insertText')
                ) {
                    onInputChange(e.target, e.target.value, { ...e.nativeEvent });
                }
            }}
            onSelect={onSelect}
            onBlur={onBlur}
            style={style}
            ref={inputRef}
        />
    );
};

export default NumberInput;
